import {AxiosHeaderValue, AxiosInstance, AxiosResponseHeaders, AxiosHeaders, AxiosError} from "axios"
import {ErrResCodeDescConst, ErrResCodeDescKey} from "@/res/consts/err-res-code-desc-const.ts"
import {ErrResTipConst} from "@/res/consts/err-res-tip-const.ts"

/**
 * 请求响应成功处理函数参数列表中 headers 参数的类型
 */
export type FulfilledHandlerHeadersPropType = AxiosResponseHeaders | Partial<AxiosHeaders & {
  Server: AxiosHeaderValue
  "Content-Type": AxiosHeaderValue
  "Content-Length": AxiosHeaderValue
  "Cache-Control": AxiosHeaderValue
  "Content-Encoding": AxiosHeaderValue
}>

/**
 * 请求响应成功处理函数的默认实现
 *
 * @param data 服务端返回的响应数据
 * @returns {any} 请求响应数据
 */
const fulfilledHandlerDefault = (data: any) => {
  return data
}

/**
 * 请求响应失败处理函数的默认实现
 *
 * @param message 响应错误提示信息
 * @param error axios 响应错误对象
 * @returns {Promise<never>} 包含 axios 错误响应对象的 Promise 对象
 */
const rejectedHandlerDefault = (message: string, error: AxiosError) => {
  error.message = message
  return Promise.reject(error)
}

/**
 * 为 axios 实例对象添加响应拦截器
 *
 * @param axios axios 实例对象
 * @param fulfilledHandler 请求响应成功的处理函数，参数列表：data-响应数据；status-响应状态；headers-响应头，
 * 默认值 {@link fulfilledHandlerDefault}
 * @param rejectedHandler 请求响应失败的处理函数，参数列表：message-响应错误提示信息；error-axios 响应错误对象，
 * 默认值 {@link rejectedHandlerDefault}
 * @returns {AxiosInstance} 添加了响应拦截器的 axios 实例对象
 */
export const addRespInterceptor = (
  axios: AxiosInstance,
  fulfilledHandler: (data: any, headers: FulfilledHandlerHeadersPropType, status: number) => any = fulfilledHandlerDefault,
  rejectedHandler: (message: string, error: AxiosError) => any = rejectedHandlerDefault
): AxiosInstance => {
  // 为 axios 实例对象添加响应拦截器
  axios.interceptors.response.use(
    // 对于成功的请求响应的处理，即成功收到服务端的响应，且是成功的响应
    (response) => {
      // 成功的请求响应的自定义统一前置预处理
      return fulfilledHandler(response.data, response.headers, response.status)
    },
    // 对于失败的请求响应的处理，即发生错误的请求响应的处理
    (error) => {
      let message = '' // 错误提示信息
      // 对于来自服务端的错误响应的处理
      // 请求成功发送到服务端，但是由于某种原因，服务端返回了错误响应
      if (error && error.response) {
        // 根据错误响应的状态码，从 ErrResCodeDescConst 中获取对应的错误提示信息
        for (let key in ErrResCodeDescConst) {
          let status = Number.parseInt(key) as ErrResCodeDescKey
          if (error.response.status === status) {
            message = ErrResCodeDescConst[status]
            break
          }
        }
        // ErrResCodeDescConst 中没有匹配的错误状态码
        if (message === '') {
          message = ErrResTipConst.CONNECT_FAILED + '，错误响应状态码：' + error.response.status
        }
      } else { // 其他类型的错误，如网络超时等
        // 网络超时
        if (error.message.includes('timeout')) message = ErrResTipConst.TIMEOUT
        else message = ErrResTipConst.CONNECT_FAILED
      }
      // 失败的请求响应的自定义统一前置预处理
      return rejectedHandler(message, error)
    }
  )
  return axios
}
